#include "StdAfx.h"
#include "util.h"
#include "global.h"
util::util(void)
{
}

util::~util(void)
{
}

/* Procedure printToken prints a token 
 * and its lexeme to the listing file
 */
void util::printToken(_TokenType token, const char* tokenString )
{ 
	switch (token)
	{ 
	case IF:
    case THEN:
    case ELSE:
    case END:
    case REPEAT:
    case UNTIL:
    case READ:
    case WRITE:
	case WHILE:
	case DO:
	case _TRUE:
	case _FALSE:
	case OR:
	case AND:
	case NOT:
	case _INT:
	case _BOOL:
	case _STRING:
		fprintf(global::listing,"(KEY,%s)\n",tokenString);
		break;
	case COMMA:
		fprintf(global::listing,"(SYM,,)\n");
		break;
	case ASSIGN: 
		fprintf(global::listing,"(SYM,:=)\n");
		break;
    case LT: 
		fprintf(global::listing,"(SYM,<)\n"); 
		break;
	case LET:
		fprintf(global::listing,"(SYM,<=)\n");
		break;
	case GT: 
		fprintf(global::listing,"(SYM,>)\n"); 
		break;
	case GET:
		fprintf(global::listing,"SYM,>=)\n");
		break;
    case EQ: 
		fprintf(global::listing,"(SYM,=)\n");
		break;
    case LPAREN: 
		fprintf(global::listing,"(SYM,()\n"); 
		break;
    case RPAREN: 
		fprintf(global::listing,"(SYM,))\n"); 
		break;
    case SEMI: 
		fprintf(global::listing,"(SYM,;)\n");
		break;
    case PLUS: 
		fprintf(global::listing,"(SYM,+)\n");
		break;
    case MINUS: 
		fprintf(global::listing,"(SYM,-)\n"); 
		break;
    case TIMES: 
		fprintf(global::listing,"(SYM,*)\n"); 
		break;
    case OVER: 
		fprintf(global::listing,"(SYM,/)\n");
		break;
    case ENDFILE: 
		fprintf(global::listing,"(SYM,EOF)\n"); 
		break;
    case NUM:
		fprintf(global::listing, "(NUM,",tokenString,")");
		fprintf(global::listing, tokenString);
		fprintf(global::listing, ")");
        break;;
    case ID:
		fprintf(global::listing, "(ID,");
		fprintf(global::listing, tokenString);
		fprintf(global::listing, ")");
        break;
	case STR:
        fprintf(global::listing, "(STR,");
		fprintf(global::listing, tokenString);
		fprintf(global::listing, ")");
		break;
    case _ERROR:
		fprintf(global::listing,"(ERROR,");
		fprintf(global::listing, tokenString);
		fprintf(global::listing, ")");
      break;
    default: /* should never happen */
		fprintf(global::listing,"Unknown token: %d\n",token);
  }
}

/* Function newStmtNode creates a new statement
 * node for syntax tree construction
 */
TreeNode * util::newStmtNode(StmtKind kind)
{ TreeNode * t = (TreeNode *) malloc(sizeof(TreeNode));
  int i;
  if (t==NULL)
    fprintf(global::listing,"Out of memory error at line %d\n",global::lineno);
  else {
    for (i=0;i<MAXCHILDREN;i++) t->child[i] = NULL;
    t->sibling = NULL;
    t->nodekind = StmtK;
    t->kind.stmt = kind;
    t->lineno = global::lineno;
  }
  return t;
}

/* Function newExpNode creates a new expression 
 * node for syntax tree construction
 */
TreeNode * util::newExpNode(ExpKind kind)
{ TreeNode * t = (TreeNode *) malloc(sizeof(TreeNode));
  int i;
  if (t==NULL)
    fprintf(global::listing,"Out of memory error at line %d\n",global::lineno);
  else {
    for (i=0;i<MAXCHILDREN;i++) t->child[i] = NULL;
    t->sibling = NULL;
    t->nodekind = ExpK;
    t->kind.exp = kind;
    t->lineno = global::lineno;
    t->type = Void;
  }
  return t;
}

/* Function copyString allocates and makes a new
 * copy of an existing string
 */
char * util::copyString(char * s)
{ int n;
  char * t;
  if (s==NULL) return NULL;
  n = strlen(s)+1;
  t = new char(n);
  if (t==NULL)
    fprintf(global::listing,"Out of memory error at line %d\n",global::lineno);
  else strcpy(t,s);
  return t;
}

/* Variable indentno is used by printTree to
 * store current number of spaces to indent
 */
static int indentno = 0;

/* macros to increase/decrease indentation */
#define INDENT indentno+=2
#define UNINDENT indentno-=2

/* printSpaces indents by printing spaces */
static void printSpaces(void)
{ int i;
  for (i=0;i<indentno;i++)
    fprintf(global::listing," ");
}

/* procedure printTree prints a syntax tree to the 
 * listing file using indentation to indicate subtrees
 */

void util::printTree( TreeNode * tree )
{ int i;
INDENT;
while (tree != NULL) {
	printSpaces();
	if (tree->nodekind==StmtK)
	{ switch (tree->kind.stmt) {
		case DeclK:
			fprintf(global::listing,"Decl:\r\n");
			break;
		case VarlistK:
			fprintf(global::listing,"Var:%s\r\n",tree->attr.name);
			break;
		case IfK:
			fprintf(global::listing,"If\r\n");
			break;
		case RepeatK:
			fprintf(global::listing,"Repeat\r\n");
			break;
		case AssignK:
			fprintf(global::listing,"Assign to: %s\r\n",tree->attr.name);
			break;
		case ReadK:
			fprintf(global::listing,"Read: %s\r\n",tree->attr.name);
			break;
		case WriteK:
			fprintf(global::listing,"Write\r\n");
			break;
		case WhileK:
			fprintf(global::listing,"While\r\n");
			break;
		case ProgramK:
			fprintf(global::listing,"Program\r\n");
			break;
		default:
			fprintf(global::listing,"Unknown ExpNode kind\r\n");
			break;
	}
	}
	else if (tree->nodekind==ExpK)
	{ switch (tree->kind.exp) {
		case OpK:
			fprintf(global::listing,"Op: ");
			printToken(tree->attr.op,"\0");
			break;
		case ConstK:
			fprintf(global::listing,"Const: %d\r\n",tree->attr.val);
			break;
		case IdK:
			fprintf(global::listing,"Id: %s\r\n",tree->attr.name);
			break;
		case StringK:
			fprintf(global::listing,"String:%s\r\n",tree->attr.name);
			break;
		default:
			fprintf(global::listing,"Unknown ExpNode kind\r\n");
			break;
	}
	}
	else fprintf(global::listing,"Unknown node kind\r\n");
	for (i=0;i<MAXCHILDREN;i++)
		printTree(tree->child[i]);
	tree = tree->sibling;
}
UNINDENT;
}